package com.dlc.shop.coupon.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.app.dto.CouponDto;
import com.dlc.shop.bean.app.dto.CouponOrderDto;
import com.dlc.shop.bean.app.dto.ProductDto;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.*;
import com.dlc.shop.bean.model.OfflineHandleEvent;
import com.dlc.shop.bean.model.ProdLang;
import com.dlc.shop.bean.param.EsProductParam;
import com.dlc.shop.bean.param.OfflineHandleEventAuditParam;
import com.dlc.shop.bean.vo.search.EsProductSearchVO;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.common.util.PageAdapter;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.coupon.common.constants.CouponStatusEnum;
import com.dlc.shop.coupon.common.constants.SuitableProdTypeEnum;
import com.dlc.shop.coupon.common.constants.ValidTimeTypeEnum;
import com.dlc.shop.coupon.common.dao.CouponMapper;
import com.dlc.shop.coupon.common.dao.CouponProdMapper;
import com.dlc.shop.coupon.common.dao.CouponUserMapper;
import com.dlc.shop.coupon.common.model.Coupon;
import com.dlc.shop.coupon.common.model.CouponProd;
import com.dlc.shop.coupon.common.model.CouponUser;
import com.dlc.shop.coupon.common.service.CouponService;
import com.dlc.shop.coupon.common.service.CouponUserService;
import com.dlc.shop.manager.impl.LangManager;
import com.dlc.shop.service.OfflineHandleEventService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/12/27.
 */
@Service
@AllArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService {
    private static final Logger logger = LoggerFactory.getLogger(CouponServiceImpl.class);

    private final CouponMapper couponMapper;
    private final CouponProdMapper couponProdMapper;
    private final CouponUserMapper couponUserMapper;
    private final CouponUserService couponUserService;
    private final OfflineHandleEventService offlineHandleEventService;
    private final ApplicationContext applicationContext;

    private final LangManager langManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "couponAndCouponProds", key = "#coupon.shopId")
    public void updateCouponAndCouponProds(@Valid Coupon coupon) {
        Integer suitableProdType = coupon.getSuitableProdType();
        Coupon couponDb = couponMapper.selectById(coupon.getCouponId());
        checkInfo(coupon, false);
        if (Objects.equals(coupon.getPutonStatus(), CouponStatusEnum.PUT_ON.getValue())) {
            if (Objects.equals(couponDb.getPutonStatus(), CouponStatusEnum.PUT_ON.getValue())) {
                coupon.setLaunchTime(couponDb.getLaunchTime());
            } else {
                coupon.setLaunchTime(new Date());
            }
        }
        couponMapper.updateCoupon(coupon);
        // 删除该优惠券下所有商品
        couponProdMapper.deleteCouponProdsByCouponId(coupon.getCouponId());
        if (suitableProdType != 0) {
            List<Long> prodIds = coupon.getCouponProds().stream().map(CouponProd::getProdId).collect(Collectors.toList());
            // 插入所有商品
            couponProdMapper.insertCouponProdsBatch(coupon.getCouponId(), prodIds);
        }
        boolean isPlatform = Objects.equals(coupon.getShopId(), Constant.PLATFORM_SHOP_ID);
        // 如果是平台优惠券进行发放，修改了投放状态的，需要更新余额充值套餐缓存
        if (isPlatform && !Objects.equals(coupon.getPutonStatus(), couponDb.getPutonStatus())) {
            applicationContext.publishEvent(new BalanceCouponEvent(coupon.getCouponId(), false));
        }
        // 不是平台端的优惠券、修改后的领取类型为平台发放、没有发生领取类型变更的，直接返回
        if(!isPlatform
                || Objects.equals(coupon.getGetWay(), 1)
                || Objects.equals(coupon.getGetWay(), couponDb.getGetWay())) {
            return;
        }
        // 处理优惠券类型从系统发放变更为用户领取时，移除用户等级绑定的优惠券（目前用户等级绑定的优惠券只支持系统发放）
        applicationContext.publishEvent(new BalanceCouponEvent(coupon.getCouponId(), true));
    }

    @Override
    @CacheEvict(cacheNames = "couponAndCouponProds", key = "#shopId")
    public void removeCouponAndCouponProdsCache(Long shopId) {
    }

    @Override
    public IPage<CouponDto> getCouponList(Page<CouponDto> page, String userId) {
        //获取优惠券列表
        List<Long> couponIds = couponMapper.getShopAvailableCouponIds(new PageAdapter(page));
        page.setTotal(couponMapper.countCouponPageByCouponDto());
        if (CollUtil.isEmpty(couponIds)) {
            page.setRecords(new ArrayList<>());
            return page;
        }
        List<CouponDto> couponDtoList = couponMapper.getCouponList(couponIds);
        getProdName(couponDtoList);
        List<CouponUser> couponUsers = couponUserMapper.listByCouponIdsAndUserId(couponIds, userId);
        Map<Long, Integer> couponUserMap = couponUsers.stream().collect(Collectors.toMap(CouponUser::getCouponId, CouponUser::getCurUserReceiveCount));
        for (CouponDto couponDto : couponDtoList) {
            if (couponUserMap.containsKey(couponDto.getCouponId())) {
                couponDto.setCurUserReceiveCount(couponUserMap.get(couponDto.getCouponId()));
                continue;
            }
            couponDto.setCurUserReceiveCount(0);
        }
        page.setRecords(couponDtoList);
        return page;
    }

    private void getProdName(List<CouponDto> couponDtoList) {
        if (CollUtil.isEmpty(couponDtoList)) {
            return ;
        }
        List<Long> ids = new ArrayList<>();
        for (CouponDto couponDto : couponDtoList) {
            for (ProductDto prod : couponDto.getProds()) {
                ids.add(prod.getProdId());
            }
        }
        Map<Long, ProdLang> prodLangMap = langManager.getProdLangMap(ids);
        for (CouponDto couponDto : couponDtoList) {
            for (ProductDto prod : couponDto.getProds()) {
                ProdLang prodLang = prodLangMap.get(prod.getProdId());
                if (Objects.nonNull(prodLang)) {
                    prod.setProdName(prodLang.getProdName());
                }
            }
        }
    }

    @Override
    public IPage<CouponDto> getCouponList(Page<CouponDto> page) {
        //获取优惠券列表
        page.setTotal(couponMapper.countCouponPageByCouponDto());
        List<Long> couponIds = couponMapper.getShopAvailableCouponIds(new PageAdapter(page));
        if (CollUtil.isEmpty(couponIds)) {
            page.setRecords(new ArrayList<>());
            return page;
        }
        List<CouponDto> couponDtoList = couponMapper.getCouponList(couponIds);
        getProdName(couponDtoList);
        page.setRecords(couponDtoList);
        return page;
    }

    @Override
    public IPage<CouponUser> getPageByUserId(PageParam<CouponUser> page, String userId, Integer status, Long shopId) {
        return couponUserMapper.getPageByUserId(page, userId, status, shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchBindCouponByIds(Map<Long, Integer> couponMap, String userId, Long shopId) {
        List<CouponUser> couponUsers = new ArrayList<>();
        Collection<Coupon> coupons = listByIds(couponMap.keySet());
        if (CollectionUtils.isEmpty(coupons)) {
            return;
        }
        for (Coupon coupon : coupons) {
            Integer sendNum = couponMap.get(coupon.getCouponId());
            for (int i = 0; i < sendNum; i++) {
                CouponUser couponUser = getCouponUser(userId, coupon, 1);
                if (couponUser == null) {
                    continue;
                }
                couponUsers.add(couponUser);
                // 更新库存
                if (couponMapper.updateCouponStocksAndVersion(coupon.getCouponId()) < 1) {
                    // 优惠券库存不足
                    logger.error("用户{}绑定优惠券{}失败，优惠券库存不足", userId, coupon.getCouponId());
                }
            }
        }
        couponUserService.saveBatch(couponUsers);
    }

    @Override
    public void bindCouponById(Long couponId, String userId, Integer couponNums, Long shopId) {
        Coupon coupon = getById(couponId);
        if (Objects.isNull(coupon)) {
            throw new YamiShopBindException("yami.coupon.no.exist");
        }
        CouponUser couponUser = getCouponUser(userId, coupon, couponNums);
        if (couponUser == null) {
            return;
        }
        List<CouponUser> couponUsers = new ArrayList<>(couponNums);
        for (Integer i = 0; i < couponNums; i++) {
            CouponUser copyCouponUser = BeanUtil.map(couponUser, CouponUser.class);
            couponUsers.add(copyCouponUser);
        }
        couponUserService.saveBatch(couponUsers, couponNums);
        // 扣减优惠券库存
        int stocks = coupon.getStocks() - couponNums;
        update(new LambdaUpdateWrapper<>(Coupon.class).set(Coupon::getStocks, stocks).eq(Coupon::getCouponId, couponId));
    }

    /**
     *  生成用户优惠券绑定对象
     * @param userId     用户id
     * @param coupon     优惠券详情
     * @param couponNums 优惠券发放数量
     * @return
     */
    private CouponUser getCouponUser(String userId, Coupon coupon, int couponNums) {
        Date nowTime = new Date();
        // 当优惠券状态不为投放时
        if (coupon.getOverdueStatus() == 0 || coupon.getPutonStatus() != 1 || coupon.getStocks() == 0) {
            // 该券无法被领取或者该券领完了!
            log.warn("yami.coupon.receive.finish");
            return null;
        }
        long count = couponUserMapper.selectCount(new LambdaQueryWrapper<CouponUser>().eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, coupon.getCouponId()));
        if (count + couponNums > coupon.getLimitNum()) {
            // 该券已达个人领取上限，无法继续领取！
            log.warn("yami.coupon.user.limit");
            return null;
        }
        CouponUser couponUser = new CouponUser();
        couponUser.setUserId(userId);
        couponUser.setStatus(1);
        couponUser.setCouponId(coupon.getCouponId());
        couponUser.setReceiveTime(nowTime);
        // 生效时间类型为固定时间
        if (Objects.equals(coupon.getValidTimeType(), ValidTimeTypeEnum.FIXED.value())) {
            couponUser.setUserStartTime(coupon.getStartTime());
            couponUser.setUserEndTime(coupon.getEndTime());
        }
        // 生效时间类型为领取后生效
        if (Objects.equals(coupon.getValidTimeType(), ValidTimeTypeEnum.RECEIVE.value())){
            if (coupon.getAfterReceiveDays() == null) {
                coupon.setAfterReceiveDays(0);
            }
            if (coupon.getValidDays() == null) {
                coupon.setValidDays(0);
            }
            couponUser.setUserStartTime(DateUtils.addDays(DateUtil.beginOfDay(nowTime), coupon.getAfterReceiveDays()));
            couponUser.setUserEndTime(DateUtils.addDays(couponUser.getUserStartTime(), coupon.getValidDays()));
        }
        couponUser.setIsDelete(0);
        return couponUser;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "couponAndCouponProds", key = "#coupon.shopId")
    public void insertCouponAndCouponProds(@Valid Coupon coupon) {
        Integer suitableProdType = coupon.getSuitableProdType();
        checkInfo(coupon, true);
        if(Objects.equals(coupon.getPutonStatus(), CouponStatusEnum.PUT_ON.getValue())) {
            coupon.setLaunchTime(new Date());
        }
        couponMapper.insert(coupon);
        if (suitableProdType != 0) {
            List<Long> prodIds = coupon.getCouponProds().stream().map(CouponProd::getProdId).collect(Collectors.toList());
            // 插入所有商品
            couponProdMapper.insertCouponProdsBatch(coupon.getCouponId(), prodIds);
        }
    }

    @Override
    public Coupon getCouponAndCouponProdsByCouponId(Long id) {
        Coupon coupon = couponMapper.getCouponAndCouponProdsByCouponId(id);
        if (CollUtil.isEmpty(coupon.getCouponProds())) {
            return coupon;
        }
        List<Long> prodIds = coupon.getCouponProds().stream().map(CouponProd::getProdId).filter(prodId -> Objects.nonNull(prodId)).collect(Collectors.toList());
        Map<Long, ProdLang> prodLangMap = langManager.getProdLangMap(prodIds);
        for (CouponProd couponProd : coupon.getCouponProds()) {
            ProdLang prodLang = prodLangMap.get(couponProd.getProdId());
            if (Objects.nonNull(prodLang)) {
                couponProd.setProdName(prodLang.getProdName());
            }
        }
        return coupon;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "couponAndCouponProds", key = "#coupon.shopId")
    public void receive(Coupon coupon, String userId) {
        //如果是积分商品，就扣除用户相应的积分
        if (Objects.equals(coupon.getCouponType(), CouponType.C2P.value())) {
            applicationContext.publishEvent(new ScoreOrderEvent(coupon.getCouponId(), null, coupon.getScorePrice()));
        }
        CouponUser couponUser = getCouponUser(coupon, userId);
        couponUserMapper.insert(couponUser);
        // 更新库存
        if (couponMapper.updateCouponStocksAndVersion(coupon.getCouponId()) < 1) {
            // 优惠券库存不足
            throw new YamiShopBindException("yami.coupon.stock.enough");
        }
    }

    private CouponUser getCouponUser(Coupon coupon, String userId) {
        Date nowTime = new Date();
        // 当优惠券状态不为投放时
        if (coupon.getOverdueStatus() == 0 || coupon.getPutonStatus() != 1) {
            // 该券无法被领取
            throw new YamiShopBindException("yami.coupon.receive.finish");
        }
        // 当优惠券不在规定时间内(类型为固定时间) 优惠券使用时间，不是领取时间，一般优惠券都是可以领，还不能用的
//        if (coupon.getValidTimeType() == 1 && (coupon.getEndTime().getTime() < nowTime.getTime() || coupon.getStartTime().getTime() > nowTime.getTime())) {
//            throw new YamiShopBindException("不在可领取的时间范围内");
//        }
        // 当优惠券无库存时
        if (coupon.getStocks() == 0) {
            // 该券领完了
            throw new YamiShopBindException("yami.coupon.receive.finish");
        }
        long count = couponUserMapper.selectCount(new LambdaQueryWrapper<CouponUser>().eq(CouponUser::getUserId, userId).eq(CouponUser::getCouponId, coupon.getCouponId()));
        if (count >= coupon.getLimitNum()) {
            // 该券已达个人领取上限，无法继续领取
            throw new YamiShopBindException("yami.coupon.user.limit");
        }
        CouponUser couponUser = new CouponUser();
        couponUser.setUserId(userId);
        couponUser.setCouponId(coupon.getCouponId());
        couponUser.setStatus(1);
        couponUser.setReceiveTime(nowTime);
        // 生效时间类型为固定时间
        if (coupon.getValidTimeType() == 1) {
            couponUser.setUserStartTime(coupon.getStartTime());
            couponUser.setUserEndTime(coupon.getEndTime());
        }
        // 生效时间类型为领取后生效
        if (coupon.getValidTimeType() == ValidTimeTypeEnum.RECEIVE.getValue()) {
            if (coupon.getAfterReceiveDays() == null) {
                coupon.setAfterReceiveDays(0);
            }
            if (coupon.getValidDays() == null) {
                coupon.setValidDays(0);
            }
            couponUser.setUserStartTime(DateUtils.addDays(DateUtil.beginOfDay(nowTime), coupon.getAfterReceiveDays()));
            couponUser.setUserEndTime(DateUtils.addDays(couponUser.getUserStartTime(), coupon.getValidDays()));
        }
        couponUser.setIsDelete(0);
        return couponUser;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeCoupon(Date now) {
        // 查询过期的优惠券
        List<Coupon> coupons = this.list(new LambdaQueryWrapper<Coupon>()
                .eq(Coupon::getValidTimeType, 1)
                .lt(Coupon::getEndTime, now));
        if (CollUtil.isEmpty(coupons)) {
            return;
        }
        List<Long> couponIds = coupons.stream().map(Coupon::getCouponId).toList();
        // 更新优惠券为过期状态
        this.update(new LambdaUpdateWrapper<Coupon>()
                .set(Coupon::getOverdueStatus, 0)
                .set(Coupon::getPutonStatus, -1)
                .in(Coupon::getCouponId, couponIds)
        );
        // 删除会员等级关联的优惠券
        applicationContext.publishEvent(new CouponOverdueEvent(couponIds));
        List<CouponDto> couponDtos = BeanUtil.mapAsList(coupons, CouponDto.class);
        // 失效弹窗
        applicationContext.publishEvent(new PopupDeleteCouponLinkEvent(couponDtos));
        // 设置店铺库存为0优惠券的状态(设为未投放状态) 没库存就消失么？
        // 像京东会有没库存的优惠券，一直展示大半天，也不消失，所以消失是用户手动下线的
//        couponMapper.updatePutonStatusByStocks();
    }

    @Override
    public void putonCoupon(Date now) {
        couponMapper.putonCoupon(now);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByCouponId(Long couponId) {
        // 获取未被删除的优惠券数量
        Long useCount = couponUserMapper.selectCount(new LambdaQueryWrapper<CouponUser>().eq(CouponUser::getCouponId, couponId).eq(CouponUser::getIsDelete, 0));
        if (useCount > 0) {
            // 该优惠券已被领取，删除失败
            throw new YamiShopBindException("yami.coupon.delete.check1");
        }

        Coupon coupon = couponMapper.selectById(couponId);
        if (Objects.isNull(coupon)) {
            // 优惠券不存在
            throw new YamiShopBindException("yami.coupon.no.exist");
        }
        if (Objects.equals(coupon.getPutonStatus(), 1)) {
            //  该优惠券已投放，删除失败
            throw new YamiShopBindException("yami.coupon.delete.check2");
        }
        //删除优惠券关联的商品
        couponProdMapper.delete(new LambdaQueryWrapper<CouponProd>().eq(CouponProd::getCouponId, couponId));
        //删除优惠券
        couponMapper.deleteById(couponId);
        // 失效弹窗
        applicationContext.publishEvent(new PopupDeleteLinkEvent(couponId, coupon.getShopId(), JumpType.COUPON.value(), null));
    }

    @Override
    public List<CouponDto> generalCouponList(String userId) {
        return couponMapper.generalCouponList(userId);
    }

    @Override
    public List<CouponDto> generalCouponList() {
        return couponMapper.generalCouponListTourist();
    }

    @Override
    public IPage<CouponDto> getCouponListByStatus(IPage<CouponDto> page, String userId, Integer status) {
        IPage<CouponDto> couponPage = couponMapper.getCouponListByStatus(page, userId, status);
        List<CouponDto> couponDtoList = couponPage.getRecords();
        for (CouponDto couponDto : couponDtoList) {
            if (Objects.equals(couponDto.getValidTimeType(), 2)) {
                Integer afterReceiveDays = couponDto.getAfterReceiveDays();
                if (Objects.isNull(couponDto.getAfterReceiveDays())) {
                    afterReceiveDays = 0;
                }
                Integer validDays = couponDto.getValidDays();
                if (validDays == null) {
                    validDays = 0;
                }
                couponDto.setStartTime(DateUtil.offsetDay(couponDto.getReceiveTime(), afterReceiveDays));
                couponDto.setEndTime(DateUtil.offsetDay(couponDto.getStartTime(), validDays));
            }
        }
        return couponPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "CouponAndCouponUser", key = "#userId")
    public void deleteUserCouponByCouponId(String userId, Long couponId) {
        couponUserMapper.deleteUserCoupon(userId, couponId);
    }

    @Override
    public List<CouponOrderDto> getCouponListByShopIds(String userId, Long shopId) {
        List<CouponOrderDto> couponOrderDtoList = couponMapper.getCouponListByShopIds(userId, shopId);
        for (CouponOrderDto couponOrderDto : couponOrderDtoList) {
            if (Objects.equals(couponOrderDto.getValidTimeType(), 2)) {
                Integer validDays = couponOrderDto.getValidDays();
                if (validDays == null) {
                    validDays = 0;
                }
                Integer afterReceiveDays = couponOrderDto.getAfterReceiveDays();
                if (afterReceiveDays == null) {
                    afterReceiveDays = 0;
                }
                couponOrderDto.setStartTime(DateUtil.offsetDay(couponOrderDto.getReceiveTime(), afterReceiveDays));
                couponOrderDto.setEndTime(DateUtil.offsetDay(couponOrderDto.getStartTime(), validDays));
            }
        }
        return couponOrderDtoList;
    }

    @Override
    @Cacheable(cacheNames = "couponAndCouponProds", key = "#shopId")
    public List<Coupon> listPutonByShopId(Long shopId) {
        return couponMapper.listPutonCouponAndCouponProdsByShopId(shopId);
    }

    @Override
    public List<Coupon> listPutonByShopIds(List<Long> shopIds, Integer getWay) {
        return couponMapper.listPutonShopIds(shopIds, getWay);
    }

    @Override
    public List<CouponDto> listCouponIdsByUserId(String userId) {
        return couponMapper.listCouponIdsByUserId(userId);
    }

    @Override
    public IPage<EsProductSearchVO> prodListByCoupon(PageParam<ProductDto> page, Coupon coupon) {
        // 优惠券所有商品可用、指定商品可用、指定商品不可用 (0全部商品参与 1指定商品参与 2指定商品不参与)
        IPage<ProductDto> productPage;
        EsProductParam productParam = new EsProductParam();
        if (!Objects.equals(coupon.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            productParam.setShopId(coupon.getShopId());
        }
        productParam.setStatus(StatusEnum.ENABLE.value());
        List<Integer> prodTypes = Arrays.asList(ProdType.PROD_TYPE_SCORE.value(), ProdType.PROD_TYPE_ACTIVE.value());
        productParam.setMustNotProdTypes(prodTypes);
        if (!Objects.equals(coupon.getSuitableProdType(), SuitableProdTypeEnum.All.getValue())) {
            List<CouponProd> couponProds = couponProdMapper.selectList(new LambdaQueryWrapper<CouponProd>().eq(CouponProd::getCouponId, coupon.getCouponId()));
            List<Long> prodIds = couponProds.stream().map(CouponProd::getProdId).collect(Collectors.toList());
            if (Objects.equals(coupon.getSuitableProdType(), SuitableProdTypeEnum.SPECIFY.getValue())) {
                productParam.setProdIds(prodIds);
            }
            if (Objects.equals(coupon.getSuitableProdType(), SuitableProdTypeEnum.SPECIFY_NO.getValue())) {
                productParam.setExcludesProdIds(prodIds);
            }
        }
        EsSearchProdEvent esSearchProdEvent = new EsSearchProdEvent();
        esSearchProdEvent.setProductParam(productParam);
        esSearchProdEvent.setPageParam(page);
        applicationContext.publishEvent(esSearchProdEvent);
        return esSearchProdEvent.getProductSearchPage();
    }

    @Override
    public IPage<Coupon> getMultiShopPage(PageParam<Coupon> page, Coupon coupon) {
        IPage<Coupon> multiShopPage = couponMapper.getMultiShopPage(page, coupon);
        for (Coupon record : multiShopPage.getRecords()) {
            record.setUseNum(couponMapper.countUseNum(record.getCouponId()) == null ? 0 : couponMapper.countUseNum(record.getCouponId()));
            record.setTakeNum(couponMapper.countTakeNum(record.getCouponId(), record.getShopId()) == null ? 0 : couponMapper.countTakeNum(record.getCouponId(), record.getShopId()));
        }
        return multiShopPage;
    }

    @Override
    public Map<String, Long> getCouponCountByStatus(String userId) {
        return couponMapper.getCouponCountByStatus(userId);
    }

    @Override
    public IPage<Coupon> getPlatformPage(PageParam<Coupon> page, Coupon coupon) {
        IPage<Coupon> couponPage = couponMapper.getPlatformPage(page, coupon);
        List<Coupon> couponList = couponPage.getRecords();
        for (Coupon temp : couponList) {
            temp.setTakeNum(couponMapper.countTakeNum(temp.getCouponId(), temp.getShopId()) == null ? 0 : couponMapper.countTakeNum(temp.getCouponId(), temp.getShopId()));
            temp.setUseNum(couponMapper.countUseNum(temp.getCouponId()) == null ? 0 : couponMapper.countUseNum(temp.getCouponId()));
        }
        return couponPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "couponAndCouponProds", key = "#coupon.shopId")
    public void offline(Coupon coupon, String offlineReason, Long sysUserId) {
        // 添加下线处理记录
        OfflineHandleEvent handleEvent = offlineHandleEventService.getBaseMapper().selectOne(new LambdaUpdateWrapper<OfflineHandleEvent>()
                .eq(OfflineHandleEvent::getHandleId, coupon.getCouponId())
                .eq(OfflineHandleEvent::getHandleType, OfflineHandleEventType.COUPON.getValue())
                .ne(OfflineHandleEvent::getStatus, OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())
        );
        if (Objects.isNull(handleEvent)) {
            handleEvent = new OfflineHandleEvent();
        }
        Date now = new Date();
        handleEvent.setHandleId(coupon.getCouponId());
        handleEvent.setHandleType(OfflineHandleEventType.COUPON.getValue());
        handleEvent.setCreateTime(now);
        handleEvent.setOfflineReason(offlineReason);
        handleEvent.setHandlerId(sysUserId);
        handleEvent.setShopId(coupon.getShopId());
        handleEvent.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        handleEvent.setUpdateTime(now);
        if (Objects.nonNull(handleEvent.getEventId())) {
            offlineHandleEventService.updateById(handleEvent);
        } else {
            offlineHandleEventService.save(handleEvent);
        }

        // 更新活动状态为下线
        couponMapper.updatePutOnStatusByCouponId(coupon.getCouponId(), CouponStatusEnum.OFFLINE.getValue());
        // 失效弹窗
        applicationContext.publishEvent(new PopupDeleteLinkEvent(coupon.getCouponId(), coupon.getShopId(), JumpType.COUPON.value(), null));
        //更新优惠券过期状态为过期
//        couponMapper.updateOverdueStatusByCouponId(coupon.getCouponId(), 0);


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditCoupon(OfflineHandleEventAuditParam offlineHandleEventAuditParam, Long sysUserId) {
        // 审核通过
        if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            // 更新优惠券为暂不投放状态
            couponMapper.updatePutOnStatusByCouponId(offlineHandleEventAuditParam.getHandleId(), CouponStatusEnum.NOT_LAUNCH.getValue());
            //更新优惠券过期状态为未过期
            couponMapper.updateOverdueStatusByCouponId(offlineHandleEventAuditParam.getHandleId(), 1);
        }
        // 审核不通过
        else if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            couponMapper.updatePutOnStatusByCouponId(offlineHandleEventAuditParam.getHandleId(), CouponStatusEnum.OFFLINE.getValue());
        }
        offlineHandleEventService.auditOfflineEvent(offlineHandleEventAuditParam, sysUserId);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditApply(Long eventId, Long couponId, String reapplyReason) {
        // 更新活动为待审核状态
        couponMapper.updatePutOnStatusByCouponId(couponId, CouponStatusEnum.WAIT_AUDIT.getValue());
        // 更新事件状态
        offlineHandleEventService.updateToApply(eventId, reapplyReason);
    }

    private void checkInfo(Coupon coupon, Boolean isSave) {
        boolean checkProd = (Objects.equals(CouponProdType.PROD_IN.value(), coupon.getSuitableProdType())
                || Objects.equals(CouponProdType.PROD_NO_IN.value(), coupon.getSuitableProdType()))
                && CollectionUtils.isEmpty(coupon.getCouponProds());
        if (checkProd) {
            // 商品不能为空
            throw new YamiShopBindException("yami.product.no.exist");
        }
        // 判断投放时间 < 生效时间
        if(coupon.getLaunchTime() != null
                && coupon.getEndTime() != null
                && coupon.getLaunchTime().compareTo(coupon.getEndTime()) > 0) {
            throw new YamiShopBindException("yami.coupon.launch.time.lt.endtime");
        }
        if (Objects.equals(coupon.getPutonStatus(), CouponStatusEnum.AUTO_LAUNCH.getValue()) && Objects.isNull(coupon.getLaunchTime())) {
            // 优惠券投放时间不能为空
            throw new YamiShopBindException("yami.coupon.launch.time.check");
        }
        Date nowTime = new Date();
        if (Objects.nonNull(coupon.getLaunchTime()) && coupon.getLaunchTime().getTime() < nowTime.getTime()) {
            // 投放时间需大于当前时间
            throw new YamiShopBindException("yami.coupon.launch.time.check1");
        }
        if (isSave) {
            if (coupon.getLimitNum() <= 0) {
                // 优惠券限领数量需大于0
                throw new YamiShopBindException("yami.coupon.limit.check");
            }
            if (coupon.getValidTimeType() == 1 && coupon.getStartTime().getTime() > coupon.getEndTime().getTime()) {
                // 开始时间需大于结束时间
                throw new YamiShopBindException("yami.coupon.time.check");
            }
        }
        // 结束时间小于等于当前时间
        if (Objects.equals(coupon.getValidTimeType(), ValidTimeTypeEnum.FIXED.value())) {
            if (coupon.getEndTime().getTime() < nowTime.getTime()) {
                coupon.setOverdueStatus(0);
                coupon.setPutonStatus(CouponStatusEnum.CANCEL.getValue());
            } else {
                coupon.setOverdueStatus(1);
            }
        }
    }
}
